﻿#include "GUISpectraDialogBase.h"
#include "ui_GUISpectraDialogBase.h"

#include "GUIFrame/MainWindow.h"
#include "GUIFrame/CentralWidget.h"
#include "GUIWidget/BrowserWidget.h"

#include "FITK_Kernel/FITKCore/FITKDataRepo.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsSpectraManager.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsPhysics.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKSpectraAlgorithm.h"

#include <QwtCustomPlot.h>
#include <qwt_scale_engine.h>
#include <qwt_plot_curve.h>
#include <QMessageBox>
#include <QFileDialog>
#include <QTextStream>
#include <QTextCodec>
#include <QSignalBlocker>
#include <QDebug>

namespace GUI
{
    GUISpectraDialogBase::GUISpectraDialogBase(int spectraDataID, bool isCreate) :
        GUIDialogBase(FITKAPP->getGlobalData()->getMainWindow()),
        _spectraDataID(spectraDataID), _isCreate(isCreate)
    {
        _ui = new Ui::GUISpectraDialogBase();
        _ui->setupUi(this);
        if (_physics) {
            _spectraManager = _physics->getFITKAcousticsSpectraManager();
        }
        init();
    }

    GUISpectraDialogBase::~GUISpectraDialogBase()
    {
        //清除临时对象
        auto spectraUiData = getCurrentSpectraUiData();
        if (spectraUiData) {
            delete spectraUiData;
            spectraUiData = nullptr;
        }

        if (_ui) {
            delete _ui;
            _ui = nullptr;
        }
    }

    void GUISpectraDialogBase::setPlotYTitle(const QString & title)
    {
        if (_plot == nullptr)return;
        _plot->setAxisYName(title);
    }

    void GUISpectraDialogBase::setDataToWidget(Acoustics::FITKAcousticsAbstractSpectra * data)
    {
        Acoustics::FITKAcousticsAbstractSpectra* spectraUiData = getCurrentSpectraUiData();
        if (data == nullptr || spectraUiData == nullptr)return;
        spectraUiData->copy(data);
    }

    void GUISpectraDialogBase::getDataFromWidget(Acoustics::FITKAcousticsAbstractSpectra * data)
    {
        Acoustics::FITKAcousticsAbstractSpectra* spectraUiData = getCurrentSpectraUiData();
        if (data == nullptr || spectraUiData == nullptr)return;
        data->copy(spectraUiData);
    }

    void GUISpectraDialogBase::init()
    {
        if (_ui == nullptr)return;
        //初始化曲线画布
        initCustomPlot();
        // 去掉帮助按钮
        setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
        //初始化界面文本
        _ui->radioButton_ComplexReallmag->setText(tr("Complex Real & lmag"));
        _ui->radioButton_ComplexMagPhase->setText(tr("Complex Mag & Phase"));
        //此公式不需要，隐藏该控件
        _ui->groupBox_Algebraic->setVisible(false);
        _ui->groupBox_Complex->setVisible(false);
        //限制输入范围
        //_ui->lineEdit_Default->setValidator(new QDoubleValidator(1, 1e10, 3, this));
        //_ui->lineEdit_UserDefined->setValidator(new QDoubleValidator(1, 1e10, 3, this));
        //_ui->lineEdit_ConstantReal->setValidator(new QDoubleValidator(-1e10, 1e10, 3, this));
        //初始化控件状态
        _ui->checkBox_AWeighting->setChecked(false);
        _ui->radioButton_Log->setChecked(true);
        _ui->radioButton_RMS->setChecked(true);
        _ui->checkBox_dB->setChecked(false);
        _ui->checkBox_dB->clicked(false);
        _ui->checkBox_AWeighting->setEnabled(false);
        _ui->groupBox_ZeroDB->setEnabled(false);
        _ui->lineEdit_UserDefined->setEnabled(false);

        //初始化表格
        QStringList headerLabels;
        headerLabels << tr("Hz") << tr("Value");
        _ui->tableWidget->setColumnCount(headerLabels.size());
        _ui->tableWidget->setHorizontalHeaderLabels(headerLabels);
    }

    void GUISpectraDialogBase::initCustomPlot()
    {
        QLayout* layout = _ui->widget_Plot->layout();
        if (layout)
        {
            _plot = new QwtCustomPlot;
            layout->addWidget(_plot);
            _plot->setAxisScaleEngine(QwtPlot::xBottom, new QwtLogScaleEngine);
            _plot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLogScaleEngine);
        }
    }

    void GUISpectraDialogBase::initConnect() 
    {
        // 连接按钮的点击信号到相应的槽函数
        connect(_ui->pushButton_Ok, &QPushButton::clicked, this, &GUISpectraDialogBase::slot_OK);
        connect(_ui->pushButton_Cancel, &QPushButton::clicked, this, &GUISpectraDialogBase::slot_Cancel);
        connect(_ui->pushButton_Import, &QPushButton::clicked, this, &GUISpectraDialogBase::slot_import);
        connect(_ui->lineEdit_Name, &QLineEdit::textEdited, this, &GUISpectraDialogBase::slot_nameEdit);
        //权重
        connect(_ui->checkBox_AWeighting, &QCheckBox::clicked, this, &GUISpectraDialogBase::slot_AWeightingClicked);
        //db
        connect(_ui->checkBox_dB, &QCheckBox::clicked, this, &GUISpectraDialogBase::slot_dBClicked);
        //应用db
        connect(_ui->pushButton_ApplyZeroDB, &QPushButton::clicked, this, &GUISpectraDialogBase::slot_applyZeroDB);
        connect(_ui->pushButton_ApplyConstant, &QPushButton::clicked, this, &GUISpectraDialogBase::slot_applyConstant);
        //零DB
        connect(_ui->radioButton_Default, &QRadioButton::clicked, this, &GUISpectraDialogBase::slot_radioDefault);
        connect(_ui->radioButton_User, &QRadioButton::clicked, this, &GUISpectraDialogBase::slot_radioUserDefault);
        connect(_ui->radioButton_Constant, &QRadioButton::clicked, this, &GUISpectraDialogBase::slot_rtnConstant);
        //log/linear
        connect(_ui->radioButton_Log, &QRadioButton::clicked, this, &GUISpectraDialogBase::slot_yAxisLogOrLinear);
        connect(_ui->radioButton_Linear, &QRadioButton::clicked, this, &GUISpectraDialogBase::slot_yAxisLogOrLinear);
        connect(_ui->radioButton_FrequencyLog, &QRadioButton::clicked, this, &GUISpectraDialogBase::slot_xAxisLogOrLinear);
        connect(_ui->radioButton_FrequencyLinear, &QRadioButton::clicked, this, &GUISpectraDialogBase::slot_xAxisLogOrLinear);
        //计算形式
        connect(_ui->radioButton_RMS, &QRadioButton::clicked, this, &GUISpectraDialogBase::slot_radioPSD);
        connect(_ui->radioButton_PSD1, &QRadioButton::clicked, this, &GUISpectraDialogBase::slot_radioPSD);
        connect(_ui->radioButton_PSD2, &QRadioButton::clicked, this, &GUISpectraDialogBase::slot_radioPSD);
        //表格文本改变
        connect(_ui->tableWidget, &QTableWidget::cellChanged, this, &GUISpectraDialogBase::slot_tableCellChanged);
    }

    void GUISpectraDialogBase::updateHzValue(QList<Acoustics::SpectraValue> HzList)
    {
        QSignalBlocker blocker(_ui->tableWidget);
        if (_ui == nullptr)return;
        _ui->tableWidget->setRowCount(0);
        int row = HzList.size();
        _ui->tableWidget->setRowCount(row);
        for (int i = 0; i < row; i++) {
            Acoustics::SpectraValue HzValue = HzList[i];
            QTableWidgetItem* itme = new QTableWidgetItem(QString::number(HzValue._hz));
            itme->setFlags(itme->flags() & ~Qt::ItemFlag::ItemIsEditable);
            _ui->tableWidget->setItem(i, 0, itme);
            _ui->tableWidget->setItem(i, 1, new QTableWidgetItem(QString::number(HzValue._value.getReal())));
        }

        updatePlot();
    }

    QList<Acoustics::SpectraValue> GUISpectraDialogBase::getUiHzValue()
    {
        QList<Acoustics::SpectraValue> hzValueList = {};
        int row = _ui->tableWidget->rowCount();
        for (int i = 0; i < row; i++) {
            Acoustics::SpectraValue hzValue;
            QTableWidgetItem* item = _ui->tableWidget->item(i, 0);
            if (item) {
                hzValue._hz = item->text().toDouble();
            }
            item = _ui->tableWidget->item(i, 1);
            if (item) {
                Core::FITKNumberComplex value;
                value.setReal(item->text().toDouble());
                hzValue._value = value;
            }
            hzValueList.append(hzValue);
        }
        return hzValueList;
    }

    Acoustics::FITKAcousticsAbstractSpectra * GUISpectraDialogBase::getCurrentSpectraData()
    {
        return FITKDATAREPO->getTDataByID<Acoustics::FITKAcousticsAbstractSpectra>(_spectraDataID);
    }

    Acoustics::FITKAcousticsAbstractSpectra * GUISpectraDialogBase::getCurrentSpectraUiData()
    {
        return FITKDATAREPO->getTDataByID<Acoustics::FITKAcousticsAbstractSpectra>(_spectraUiDataID);
    }

    void GUISpectraDialogBase::updatePlot()
    {
        if (_plot == nullptr)return;
        QVector<float> hz = {}, real = {};
        QList<Acoustics::SpectraValue> spectrValueList = getUiHzValue();
        for (Acoustics::SpectraValue spectrValue : spectrValueList) {
            hz.append(spectrValue._hz);
            real.append(spectrValue._value.getReal());
        }
        _plot->setCurveData(hz, real);
        _plot->replot();
    }

    void GUISpectraDialogBase::updateZeroDBUnit()
    {

    }

    void GUISpectraDialogBase::updateConstantAndRealValueUnit(const QString & unit)
    {
        if (_ui->checkBox_AWeighting->isChecked() && _ui->checkBox_dB->isChecked()) {
            _ui->label_ConstantRealUnit->setText(tr("dBA"));
            _ui->radioButton_RealValues->setText(tr("Real Values \n(%1,ref = %2)").arg(tr("dBA")).arg(_uiCurrentZeroDBValue));
        }
        else if (_ui->checkBox_dB->isChecked()) {
            _ui->label_ConstantRealUnit->setText(tr("dB"));
            _ui->radioButton_RealValues->setText(tr("Real Values \n(%1,ref = %2)").arg(tr("dB")).arg(_uiCurrentZeroDBValue));
        }
        else {
            _ui->label_ConstantRealUnit->setText(unit);
            if (unit.isEmpty()) {
                _ui->radioButton_RealValues->setText(tr("Real Values"));
            }
            else {
                _ui->radioButton_RealValues->setText(tr("Real Values \n(%1)").arg(unit));
            }
        }
    }

    void GUISpectraDialogBase::frontCalculate()
    {
        Acoustics::FITKAcousticsAbstractSpectra* spectraUIData = getCurrentSpectraUiData();
        if (spectraUIData == nullptr)return;
        Acoustics::FITKAcousticsAbstractSpectra::AcousticsSpectraType type = spectraUIData->getSpectraType();
        Acoustics::FITKSpectraAlgorithm* alg = spectraUIData->getSpectraAlg();
        if (alg == nullptr)return;
        //清空计算参数
        alg->clear();
        QList<Acoustics::SpectraValue> result = spectraUIData->getSpectraValue();

        //PSD计算
        bool isPsd = false;
        if (_ui->radioButton_RMS->isChecked()) {
            alg->setCalcType(0);
        }
        else if (_ui->radioButton_PSD1->isChecked()) {
            isPsd = true;
            alg->setCalcType(1);
        }
        else if (_ui->radioButton_PSD2->isChecked()) {
            isPsd = true;
            if (type == Acoustics::FITKAcousticsAbstractSpectra::Acceleration) {
                alg->setCalcType(2);
            }
            else {
                //计算PSD g^2时需先计算PSD m/s
                alg->setCalcType(1);
                alg->calcPSD(true, result);
                result = alg->getResults();
                alg->setCalcType(2);
            }
        }
        alg->calcPSD(true, result);
        result = alg->getResults();

        //正向计算
        if (_ui->checkBox_dB->isChecked()) {
            //DB计算
            this->slot_yAxisLogOrLinear(true);
            alg->setDBAlgConfig(true, _uiCurrentZeroDBValue);
            alg->calcDBData(true, result);
            result = alg->getResults();
        }
        if (_ui->checkBox_dB->isChecked() && _ui->checkBox_AWeighting->isChecked()) {
            //A权计算
            alg->setAWeighting(true);
            if (isPsd == true) {
                //PSD下的A权是RMS两倍
                alg->calcAWeighting(true, result, 2);
            }
            else {
                alg->calcAWeighting(true, result, 1);
            }
            result = alg->getResults();
        }

        updateHzValue(result);
    }

    void GUISpectraDialogBase::backCalculate()
    {
        Acoustics::FITKAcousticsAbstractSpectra* spectraUIData = getCurrentSpectraUiData();
        if (spectraUIData == nullptr)return;
        Acoustics::FITKAcousticsAbstractSpectra::AcousticsSpectraType type = spectraUIData->getSpectraType();
        Acoustics::FITKSpectraAlgorithm* alg = spectraUIData->getSpectraAlg();
        if (alg == nullptr)return;
        QList<Acoustics::SpectraValue> result = this->getUiHzValue();

        //清空计算参数
        alg->clear();

        //判断是否会进行PSD计算
        bool isPsd = false;
        if (_ui->radioButton_RMS->isChecked() == true) {
            alg->setCalcType(0);
        }
        else if (_ui->radioButton_PSD1->isChecked() == true) {
            alg->setCalcType(1);
            isPsd = true;
        }
        else if (_ui->radioButton_PSD2->isChecked() == true) {
            alg->setCalcType(2);
            isPsd = true;
        }
        //计算DB
        if (_ui->checkBox_dB->isChecked() == true) {
            if (_ui->checkBox_AWeighting->isChecked() == true) {
                //A权计算
                alg->setAWeighting(true);
                if (isPsd == true) {
                    //PSD下的A权是RMS两倍
                    alg->calcAWeighting(false, result, 2);
                }
                else {
                    alg->calcAWeighting(false, result, 1);
                }
                result = alg->getResults();
            }
            //DB计算
            this->slot_yAxisLogOrLinear(true);
            alg->setDBAlgConfig(true, _uiCurrentZeroDBValue);
            alg->calcDBData(false, result);
            result = alg->getResults();
        }

        //PSD计算
        if (_ui->radioButton_RMS->isChecked()) {
            alg->setCalcType(0);
        }
        else if (_ui->radioButton_PSD1->isChecked()) {
            alg->setCalcType(1);
        }
        else if (_ui->radioButton_PSD2->isChecked()) {
            if (type == Acoustics::FITKAcousticsAbstractSpectra::Acceleration) {
                alg->setCalcType(2);
            }
            else {
                //PSD g^2反向计算时先计算为PSD m/s
                alg->setCalcType(2);
                alg->calcPSD(false, result);
                //反算PSD m/s
                result = alg->getResults();
                alg->setCalcType(1);
            }
        }
        alg->calcPSD(false, result);
        result = alg->getResults();
        spectraUIData->setSpectraValue(result);
    }

    void GUISpectraDialogBase::updateTableWidget()
    {
        //从数据结构中获取表单对象
        GUI::MainWindow* mw = dynamic_cast<GUI::MainWindow*>(FITKAPP->getGlobalData()->getMainWindow());
        //切换到浏览页
        mw->getCentralWidget()->getGraphArea()->switch2AWindow(GUI::GraphAbstractSubWin::SubWinType::Browser);
        GUI::BrowserWidget* bw = mw->getCentralWidget()->getGraphArea()->getCurrentWindow<GUI::BrowserWidget>();
        if (bw == nullptr) return;
        bw->updateTable();
    }

    void GUISpectraDialogBase::updateZeroDBWidget(bool isUseDefined)
    {
        _ui->lineEdit_Default->setEnabled(false);
        if (isUseDefined == true) {
            _ui->radioButton_User->setChecked(true);
            _ui->lineEdit_UserDefined->setEnabled(true);
        }
        else {
            _ui->radioButton_Default->setChecked(true);
            _ui->lineEdit_UserDefined->setEnabled(false);
        }
    }

    void GUISpectraDialogBase::setPlotTitle(const QString & title)
    {
        if (_plot) {
            _plot->setTitle(title);
        }
    }

    void GUISpectraDialogBase::changeUiRealValue(const double& real)
    {
        QList<Acoustics::SpectraValue> spectraList = this->getUiHzValue();
        for (int i = 0; i < spectraList.size(); i++) {
            spectraList[i]._value.setReal(real);
        }
        updateHzValue(spectraList);
    }

    void GUISpectraDialogBase::radioPSDClickEvent()
    {
        frontCalculate();
        updateZeroDBUnit();
        upateFormType();
    }

    void GUISpectraDialogBase::slot_OK()
    {
        if (_spectraManager == nullptr)return;
        if (_isCreate) {
            QString name = _ui->lineEdit_Name->text();
            if (_spectraManager->getDataByName(name)) {
                QMessageBox::warning(this, tr("Warning"), tr("%1 is exist!").arg(name), QMessageBox::Ok);
                return;
            }
            Acoustics::FITKAcousticsAbstractSpectra* newSpectra = this->createNewSpectra();
            if (newSpectra == nullptr)return;
            getDataFromWidget(newSpectra);
            newSpectra->setDataObjectName(name);
            _spectraManager->appendDataObj(newSpectra);
        }
        else {
            Acoustics::FITKAcousticsAbstractSpectra* spectra = this->getCurrentSpectraData();
            if (spectra == nullptr)return;
            getDataFromWidget(spectra);
        }
        //更新表格
        updateTableWidget();
        accept();
    }

    void GUISpectraDialogBase::slot_Cancel()
    {
        reject();
    }

    void GUISpectraDialogBase::slot_import()
    {
        // 打开文件对话框，选择文件
        /*QString path = QFileDialog::getOpenFileName(nullptr, tr("Open File"), "", tr("Text Files (*.txt)"));
        // 如果没有选择文件，直接返回
        QFile file(path);
        if (!file.exists())
        {
            return;
        }
        // 打开文件
        if (!file.open(QIODevice::ReadOnly))
        {
            return;
        }

        QList<Acoustics::SpectraValue> valueList;
        QTextStream textStream(&file);

        while (!textStream.atEnd())
        {
            QString line = textStream.readLine();
            // 如果是空行，跳过
            if (line.isEmpty())
            {
                continue;
            }
            // 按空格或制表符分隔字符串，去掉空的部分
            QStringList lineList = line.split(QRegExp("[\\s]+"), QString::SkipEmptyParts);
            // 至少两个值（频率和数值），解析并存储
            if (lineList.size() >= 2)
            {
                Acoustics::SpectraValue spectra;
                spectra._hz = lineList[0].toDouble();  // 频率
                spectra._value.setReal(lineList[1].toDouble());  // 对应的值
                valueList.append(spectra);  // 添加到列表中
            }
        }

        file.close();
        updateData(valueList);*/
    }

    void GUISpectraDialogBase::slot_nameEdit()
    {
        Acoustics::FITKAcousticsAbstractSpectra * spectraUiData = getCurrentSpectraUiData();
        if (spectraUiData == nullptr)return;
        QString name = _ui->lineEdit_Name->text();
        spectraUiData->setDataObjectName(name);
    }

    void GUISpectraDialogBase::slot_AWeightingClicked(bool checked)
    {
        Q_UNUSED(checked);
        _ui->lineEdit_UserDefined->setText(QString::number(_uiCurrentZeroDBValue));
        frontCalculate();
        this->updatePlotYTitle();
        updateConstantAndRealValueUnit("");
    }

    void GUISpectraDialogBase::slot_dBClicked(bool checked)
    {
        if (checked) {
            _ui->radioButton_Linear->setChecked(true);
            _ui->checkBox_AWeighting->setEnabled(true);
            _ui->widget_LogAndLin->setEnabled(false);
            _ui->groupBox_ZeroDB->setEnabled(true);
        }
        else {
            _ui->widget_LogAndLin->setEnabled(true);
            _ui->checkBox_AWeighting->setChecked(false);
            _ui->checkBox_AWeighting->setEnabled(false);
            _ui->groupBox_ZeroDB->setEnabled(false);
        }
        _ui->lineEdit_UserDefined->setText(QString::number(_uiCurrentZeroDBValue));
        frontCalculate();
        this->updatePlotYTitle();
        updateConstantAndRealValueUnit("");
    }

    void GUISpectraDialogBase::slot_applyZeroDB()
    {
        if (_ui->radioButton_Default->isChecked()) {
            _uiCurrentZeroDBValue = _ui->lineEdit_Default->text().toDouble();
        }
        else {
            _uiCurrentZeroDBValue = _ui->lineEdit_UserDefined->text().toDouble();
        }
        this->frontCalculate();
        this->updatePlotYTitle();
        updateConstantAndRealValueUnit("");
    }

    void GUISpectraDialogBase::slot_radioDefault(bool checked)
    {
        if (checked) {
            _ui->lineEdit_Default->setEnabled(true);
            _ui->lineEdit_UserDefined->setEnabled(false);
        }
    }

    void GUISpectraDialogBase::slot_radioUserDefault(bool checked)
    {
        if (checked) {
            _ui->lineEdit_Default->setEnabled(false);
            _ui->lineEdit_UserDefined->setEnabled(true);
        }
    }

    void GUISpectraDialogBase::slot_applyConstant()
    {
        double real = _ui->lineEdit_ConstantReal->text().toDouble();
        changeUiRealValue(real);
        backCalculate();
    }

    void GUISpectraDialogBase::slot_rtnConstant(bool checked)
    {
        Q_UNUSED(checked);
        _ui->lineEdit_ConstantReal->setEnabled(_ui->radioButton_Constant->isChecked());
    }

    void GUISpectraDialogBase::slot_xAxisLogOrLinear(bool checked)
    {
        Q_UNUSED(checked);

        if (!_plot)
        {
            return;
        }

        if (_ui->radioButton_FrequencyLog->isChecked())
            _plot->setAxisScaleEngine(QwtPlot::xBottom, new QwtLogScaleEngine);
        if (_ui->radioButton_FrequencyLinear->isChecked())
            _plot->setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine);
    }

    void GUISpectraDialogBase::slot_yAxisLogOrLinear(bool checked)
    {
        Q_UNUSED(checked);

        if (!_plot)
        {
            return;
        }

        if (_ui->radioButton_Log->isChecked())
            _plot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLogScaleEngine);
        if (_ui->radioButton_Linear->isChecked())
            _plot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
    }

    void GUISpectraDialogBase::slot_tableCellChanged(int row, int column)
    {
        Q_UNUSED(row);
        Q_UNUSED(column);
        updatePlot();
        backCalculate();
    }

    void GUISpectraDialogBase::slot_radioPSD()
    {
        radioPSDClickEvent();
    }
}
